package com.lance.answer.question_answer.xj_new;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.lance.answer.dto.CompleteInfo;
import com.lance.answer.dto.CourseInfo;
import com.lance.answer.dto.XjUserCourseInfo;
import com.lance.answer.gui.answer.AnswerObject;
import com.lance.answer.gui.answer.DealJsonString;
import com.lance.answer.gui.answer.Util;
import com.lance.answer.util.HttpUtil;
import com.lance.answer.util.XinJiangUtil;
import com.lance.answer.util.image_valid.VerifyCodeUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

/**
 * @author fengx
 * 新疆一体化答题-考试
 *
 * </p>
 */

@Slf4j
public class BatchDoXJAnswerTestingTaskTmp extends Thread{


    private static List<WebElement> findWeElements(WebDriver driver, String cssSelector, int second) {
        return (new WebDriverWait(driver, Duration.ofSeconds(second))).until((ExpectedCondition<List<WebElement>>) d -> {
            assert d != null;
            return d.findElements(By.cssSelector(cssSelector));
        });
    }

    private String driverPath;
    private LinkedBlockingDeque<CourseInfo> userCourses;

    public BatchDoXJAnswerTestingTaskTmp(String driverPath, LinkedBlockingDeque<CourseInfo> userCourses) {
        this.driverPath = driverPath;
        this.userCourses = userCourses;
    }

    @SneakyThrows
    @Override
    public void run() {

        while (userCourses.size() > 0) {
            CourseInfo courseInfo = userCourses.take();
            String userName = courseInfo.getUser();
            String password = courseInfo.getPwd();
            String subjectName = courseInfo.getSubjectName();
            int openCourseId = courseInfo.getOpenCourseId();
            Map<String, AnswerObject> answerMap = courseInfo.getAnswerMap();
            log.info("任务：{} 剩余 {} 行，当前课程：{} 用户名：{} 密码：{}",
                    Thread.currentThread().getName(),userCourses.size(),subjectName,userName, password);
            completeHomework(subjectName, openCourseId, answerMap, userName, password);
            //log.info("{} 开始执行刷题任务",Thread.currentThread().getName());

        }

        if (userCourses.size() == 0) {
            log.info("课程所有用户均已执行完毕，系统将在20min后结束");
            TimeUnit.MINUTES.sleep(20);
            return;
        }
    }




    public static void completeHomework(String majorName, int openCourseId, Map<String, AnswerObject> answerMap, String username, String pwd) {

        boolean isComplete = false;

        try {

            File directory = new File("E:\\answerInfo一体化\\" + majorName);
            if (!directory.exists()) {
                directory.mkdirs();
            }

            String filePath = "E:\\answerInfo一体化\\" + majorName + "\\" + username + "-testing.txt";
            File userCompleteInfoFile = new File(filePath);
            InputStream inputStream = new FileInputStream(userCompleteInfoFile);
            String completeInfoStr = IOUtils.toString(inputStream, "UTF-8");
            List<CompleteInfo> completeInfoList = JSONObject.parseArray(completeInfoStr, CompleteInfo.class);
            if (null != completeInfoList) {
                for (CompleteInfo info : completeInfoList) {
                    if ("没有这门课程！".equals(info.getSummary()) || "完成了这门课程！".equals(info.getSummary()) || "该课程没有考试！".equals(info.getSummary())) {
                        isComplete = true;
                        break;
                    }
                }
            }
        } catch (Exception e) {
            // e.printStackTrace();
        }
        if (isComplete) {
            return;
        }
        WebDriver driver = Util.getDriver("c:\\ynouAutoStudy\\chromedriver.exe");

        try {

            int sid = 0;
            driver.get("https://xjskk.open.com.cn/stuspace-auth/#/login");
            XinJiangUtil.studentLogin(driver, username, pwd);
            Thread.sleep(2000);

            // FIXME 有的人报了多个专业
            for (WebElement we : findWeElements(driver, "div[class='part']", 20)) {
                if (majorName.equals(we.getAttribute("title"))) {
                    we.click();
                    Thread.sleep(5000);
                    break;
                }

                // FIXME 正式要删掉
                if (!Strings.isNullOrEmpty(we.getAttribute("title")) && we.getAttribute("title").contains("2021年秋季")) {
                    we.click();
                    break;
                }
                if (!Strings.isNullOrEmpty(we.getAttribute("title")) && we.getAttribute("title").contains("2021年春季")) {
                    we.click();
                    break;
                }
                if (!Strings.isNullOrEmpty(we.getAttribute("title")) && we.getAttribute("title").contains("2020年春季")) {
                    we.click();
                    break;
                }
                if (!Strings.isNullOrEmpty(we.getAttribute("title")) && we.getAttribute("title").contains("2020年秋季")) {
                    we.click();
                    break;
                }
                // FIXME 正式要删掉

            }

            Set<Cookie> cookies = driver.manage().getCookies();
            String studentSpaceProfile = Util.getStudentSpaceProfile2(cookies);
            String authorization = Util.getAuthorization2(cookies);
            Map<String, String> heads = Maps.newHashMap();
            String cookie = Util.getCookie(cookies);
            initHeads(heads, studentSpaceProfile, authorization);

            String getCourseInfoUrl = "https://xjskk.open.com.cn/api/student/student-space-service/courses/" + "getStudentCourses?pageNumber=1&pageSize=2000000&status=1&courseNameCode=";
            XjUserCourseInfo userCourseInfo = JSON.parseObject(HttpUtil.get(getCourseInfoUrl, cookie, heads), XjUserCourseInfo.class);
            for (XjUserCourseInfo.ContentDTO.ItemsDTO items : userCourseInfo.getContent().getItems()) {
                if (openCourseId == items.getOpenCourseId()) {
                    sid = items.getSelectCourseId();
                    break;
                }
            }

            driver.get("https://xjskk.open.com.cn/stuspace/#/course?oId=" + openCourseId + "&sId=" + sid);

            // 获取当前已经刷了的课程项目
            Thread.sleep(5000);
            for (WebElement liWe : findWeElements(driver, "li[class='fl']", 30)) {
                if ("考试".equals(liWe.getText().trim())) {
                    liWe.click();
                    break;
                }
            }
            Thread.sleep(5000);


            // v-btn theme--light primary


            boolean isCommit = false;
            try {
                WebElement textArea = driver.findElement(By.className("exam-name"));
                WebElement webElement = Util.findByCssSelector(textArea, "span[class='el-tag el-tag--small']");
                if (webElement != null && webElement.getText().equals("已批阅")) {
                    isCommit = true;
                }
                if(webElement == null){
                    // 该课程没有考试！
                    try {

                        List<CompleteInfo> completeInfoList = Lists.newArrayList();

                        CompleteInfo info = new CompleteInfo();
                        info.setSummary("该课程没有考试！");
                        completeInfoList.add(info);
                        FileUtils.write(new File("E:\\answerInfo一体化\\" + majorName + "\\" + username + "-testing.txt"), JSONObject.toJSONString(completeInfoList, SerializerFeature.PrettyFormat), "utf-8");
                        closeDriver(driver);
                        return;
                    } catch (Exception e) {

                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 批阅就退出。
            if (isCommit) {
                try {

                    List<CompleteInfo> completeInfoList = Lists.newArrayList();

                    CompleteInfo info = new CompleteInfo();
                    info.setSummary("完成了这门课程！");
                    completeInfoList.add(info);
                    FileUtils.write(new File("E:\\answerInfo一体化\\" + majorName + "\\" + username + "-testing.txt"), JSONObject.toJSONString(completeInfoList, SerializerFeature.PrettyFormat), "utf-8");
                    closeDriver(driver);
                    return;
                } catch (Exception e) {

                }
            }

            WebElement btnWe = findWeElements(driver, "button[class='v-btn theme--light primary']", 30).get(0);
            // TODO 开始答题
            btnWe.click();
            Util.switchToLast(driver);
            Thread.sleep(2000);
            Thread.sleep(new Random().nextInt(10)*1000);

            // <img data-v-f5362150="" src="" alt="">
            // todo 拿到img的src

            //是否相等
            // 验证码是否正确
            boolean isGetCorrectCode = false;
            int repeatCnt = 0;
            int repeatCntMax = 12;

            // 勾选  已阅读并了解考试要求及注意事项
            driver.findElement(By.xpath("//*[@id=\"app\"]/div/div/div[2]/div/div[2]/p/span[2]")).click();
            boolean isGoOn = true;
            boolean isWait = false;
            while (!isGetCorrectCode) {
                try {
                    Thread.sleep(new Random().nextInt(5)*1000);
                    if (repeatCnt > repeatCntMax) {
                        isGoOn = false;
                        isWait = true;
                        log.info("超出重试次数");
                        break;
                    }
                    WebElement imgElement = driver.findElement(By.xpath("//*[@id=\"app\"]/div/div/div[2]/div/div[2]/div/p[2]/img"));
                    String code = VerifyCodeUtils.read(imgElement.getAttribute("src"));
                    driver.findElement(By.className("el-input__inner")).clear();
                    Thread.sleep(1000);
                    driver.findElement(By.className("el-input__inner")).sendKeys(new String[]{code});
                    // driver.findElement(By.className("el-input__inner")).click();
                    Thread.sleep(2000);
                    confirmAnswer(driver);
                    // 这里可以判断有没有进入答题画面，没有就 点击刷新验证码
                    // step1:  判断有没有进入答题画面
                    // 这里一定要休眠5S  给系统刷新页面的时间
                 //   Thread.sleep(4 * 1000);

                    // 在这里检查页面有没有出现提交考试的按钮，如果有说明进入了考试页面；
                    boolean isSuccess = false;
                    String commitBtn = "提交考试";
                    for (WebElement confirmBtn : driver.findElements(By.cssSelector("button[type='button']"))) {
                        if (confirmBtn.getText().equals(commitBtn)) {
                            isSuccess = true;
                            isGetCorrectCode = true;
                            break;
                        }
                    }
                    // 在这里检查页面有没有出现提交考试的按钮，如果有说明进入了考试页面；

                    // 如果没有成功 step2:点击刷新验证码
                    if (!isSuccess) {
                        repeatCnt++;
                        driver.findElement(By.xpath("//*[@id=\"app\"]/div/div/div[2]/div/div[2]/div/p[2]/i")).click();
                        Thread.sleep(2000);
                    }

                } catch (Exception e) {
                    repeatCnt++;
                    e.printStackTrace();
                }
            }

            // 验证码输入失败
            if (!isGoOn) {
                closeDriver(driver);
                return;
            }
            // 手动输入验证码
            while (isWait) {
                try {
                    Thread.sleep(30000);
                    // 在这里检查页面有没有出现提交考试的按钮，如果有说明进入了考试页面；
                    String commitBtn = "提交考试";
                    for (WebElement confirmBtn : driver.findElements(By.cssSelector("button[type='button']"))) {
                        if (confirmBtn.getText().equals(commitBtn)) {
                            isWait = false;
                            break;
                        }
                    }
                    // 在这里检查页面有没有出现提交考试的按钮，如果有说明进入了考试页面；
                    // 如果没有成功 step2:点击刷新验证码

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            //   confirmAnswer(driver);

            int time = Util.getTime(driver.findElement(By.className("time")).getText().trim());
//            System.err.println("time:" + time);
//            if (time < 4150) {
//                btnClick(driver, "提交考试");
//                Thread.sleep(5000);
//                btnClick(driver, "确定");
//                closeDriver(driver);
//                return;
//            }


            Thread.sleep(5000);
            // 3、开始答题 TODO list-children-class children-div-top
            List<WebElement> questionWeList = findWeElements(driver, "div[class^='list-children-class']", 20);
            doAnswer(driver, questionWeList, answerMap);
            // FIXME TODO 要提交答案
            // 4、提交测验
//                <h4 data-v-f5362150="" class="time">01:16:05</h4>
            // FIXME  判断考试剩余时间  当只剩余70分钟时（答题时间需要超过20分钟），提交试卷

             time = Util.getTime(driver.findElement(By.className("time")).getText().trim());
            System.err.println("time:" + time);
            if (time < 4150) {
                btnClick(driver, "提交考试");
                Thread.sleep(5000);
                btnClick(driver, "确定");
            }
            // FIXME  判断考试剩余时间  当只剩余1个小时时，提交试卷
//            int time = Util.getTime(driver.findElement(By.className("time")).getText().trim());
//            System.err.println("time:" + time);
//            int twice = 0;
//            while (time > 4150) {
//                twice++;
//                Thread.sleep(60 * 1000);
//                time = Util.getTime(driver.findElement(By.className("time")).getText().trim());
//                System.err.println("time:" + time);
//                if (twice > 23) {
//                    break;
//                }
//            }
//            // FIXME  判断考试剩余时间  当只剩余1个小时时，提交试卷
//            btnClick(driver, "提交考试");
//            Thread.sleep(5000);
//            btnClick(driver, "确定");
            // FIXME  判断考试剩余时间  当只剩余70分钟时（答题时间需要超过20分钟），提交试卷

            // 4、提交测验 // 不需要提交 2012-12-12
            Thread.sleep(5000);
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("Exception !!!!!!!!!!!!!!!!!");
        } finally {
            closeDriver(driver);
        }
    }


    private static void closeDriver(WebDriver driver) {
        try {
            driver.close();
            driver.quit();
        } catch (Exception e) {

        }
    }

    private static void doAnswer(WebDriver driver, List<WebElement> questionWeList, Map<String, AnswerObject> answerMap) throws Exception {

        // fixme 每次答一个题睡眠2S
        Thread.sleep(2 * 1000);
        // fixme

        System.err.println("questionWeListSize：" + questionWeList.size());

        Map<String, Integer> ueditorIndexMap = Maps.newHashMap();
        ueditorIndexMap.put("ueditorIndex", 0);
        for (WebElement questionWe : questionWeList) {
            try {
             //   Thread.sleep(1 * 1000);
                WebElement titleWe = questionWe.findElement(By.className("children-value-class"));
                // fixme
                String title = titleWe.getText();
                title = Util.dealContent(title);
                title = DealJsonString.delHTMLTag(title);
                AnswerObject answerObject = answerMap.get(title);
                if (answerObject == null) {
                    continue;
                }
                System.err.println("answerObject:" + JSONObject.toJSONString(answerObject));
                String questionType = answerObject.getQuestionType();

                switch (questionType) {
                    case "1":
                    case "2":
                    case "3": {
                        // 单选 多选 判断
                        doChoiceExercise(questionWe, answerObject.getAnswers());
                        break;
                    }
                    case "4":
                    case "6": {
                        doGapFilling(driver, questionWe, answerObject.getAnswers(), ueditorIndexMap);
                        break;
                    }
                    default: {
                        throw new Exception("不支持的题型!" + questionType + answerObject.getQuestionTitle());
                    }
                }
            } catch (Exception e) {

            }
        }
    }

    /**
     * 填空题
     *
     * @param answerElement answerElement
     * @param realAnswers   realAnswers
     */
    private static void doGapFilling(WebDriver driver, WebElement answerElement, List<String> realAnswers, Map<String, Integer> ueditorIndexMap) {

        try {
            Thread.sleep(500);
            List<WebElement> divList = answerElement.findElements(By.cssSelector("div[class='virtualInput']"));
            System.err.println("divList：Size:" + divList.size());
            for (int i = 0; i < divList.size(); i++) {
                WebElement div = divList.get(i);
                //   input.clear();
                div.click();
                Thread.sleep(2000);
                Integer index = ueditorIndexMap.get("ueditorIndex");
                WebElement iframe = driver.findElement(By.id("ueditor_" + index));
                System.err.println("realAnswers.get(i):" + realAnswers.get(i));
                String js = "document.getElementById('" + iframe.getAttribute("id") + "').contentWindow.document.body.innerText = '" + realAnswers.get(i) + "'";
                ((JavascriptExecutor) driver).executeScript(js);
                ueditorIndexMap.put("ueditorIndex", ++index);
                Thread.sleep(2000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private static void doChoiceExercise(WebElement answerElement, List<String> realAnswers) {
        try {
            Thread.sleep(500);
            // 遍历题目的每一个选项
            for (WebElement singleAnswerElement : answerElement.findElements(By.cssSelector("div[class='clearfix']"))) {
                String answerContent = singleAnswerElement.findElement(By.cssSelector("span[class='option-value-class']")).getText();
                //兼容特殊字符
                answerContent = Util.dealContent(answerContent);
                System.err.println("answerContent:" + answerContent);
                // 找到单选框或复选框
                // el-checkbox el-radio
                WebElement labelElement = singleAnswerElement.findElement(By.cssSelector("label[class^='el-']"));

                // 找到真正的点击按钮 el-radio__input el-checkbox__input
                WebElement realClickElement = singleAnswerElement.findElement(By.cssSelector("span[class^='el-']"));

                String labelClass = labelElement.getAttribute("class");
                System.err.println("labelClass:" + labelClass);

                // 单选或者判断题
                WebElement clickWebElement = null;
                if (labelClass.contains("radio")) {
                    clickWebElement = labelElement.findElement(By.cssSelector("input[type='radio']"));
                }
                if (labelClass.contains("checkbox")) {
                    clickWebElement = labelElement.findElement(By.cssSelector("input[type='checkbox']"));
                }
                // FIXME 判断题0：对 1：错
                // 这里的ID是每个选项的ID answerContent是每个选项的内容
                for (String realAnswer : realAnswers) {
                    System.err.println("origin:" + answerContent);
                    // if (answerContent.equals(realAnswer)) {
                    realAnswer = Util.dealContent(realAnswer);
                    realAnswer = DealJsonString.delHTMLTag(realAnswer);
                    answerContent = DealJsonString.delHTMLTag(answerContent);
                    if (answerContent.equals(realAnswer)) {
                        System.err.println("realAnswer:" + realAnswer);
                        assert clickWebElement != null;
                        if (!clickWebElement.isSelected()) {
                            realClickElement.click();
                        }
                    }
                }


            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    public static void initHeads(Map<String, String> heads, String studentSpaceProfile, String authorization) {
        heads.put("referer", "https://xjskk.open.com.cn/stuspace/");
        heads.put("authority", "xjskk.open.com.cn");
        heads.put("path", "/api/student/student-space-service/resources/updateResourceTrace");
        heads.put("scheme", "scheme");
        heads.put("open-student-space-profile", studentSpaceProfile);
        heads.put("origin", "https://xjskk.open.com.cn");
        heads.put("authorization", authorization);
    }


    public static void confirmAnswer(WebDriver driver) {
        List<WebElement> saveButtons = findWeElements(driver, "button[type='button']", 30);
        if (!CollectionUtils.isEmpty(saveButtons)) {
            for (WebElement webElement : saveButtons) {
                String text = webElement.getText();
                System.err.println("text:" + text);
                if (text.contains("确 定")) {
                    webElement.click();
                    break;
                }
            }
        }
    }

    public static void btnClick(WebDriver driver, String btnName) {
        for (WebElement confirmBtn : driver.findElements(By.cssSelector("button[type='button']"))) {
            if (confirmBtn.getText().equals(btnName)) {
                confirmBtn.click();
                break;
            }
        }
    }


}
